﻿using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Imaginecup.shareData;
using Imaginecup.util.vertex2D;

namespace Imaginecup.util.bladeEffect
{
    public class CBlade
    {
        private List<Vector2> m_Path;
        private int m_PointLimit;

        private Vertex2DBuffer m_PosTexVerticeBuffer;

        private bool m_bDecreaseState;
        private bool m_bEndState;

        private Texture2D m_Texture;

        private float m_Width;
        private const int DISTANCE_TO_INTERPOLATE = 10;

        private RasterizerState nonCull = new RasterizerState()
        {
            CullMode = CullMode.None
        }; 

        private CBlade(){}


        public void SetTexture(Texture2D a_texture)
        {
            this.m_Texture = a_texture;
        }

        public void SetDecreaseState()
        {
            m_bDecreaseState = true;
        }     

        public static CBlade BladeWithMaximumPoint(int limit , int width)
        {
            CBlade blade = new CBlade();
            return blade.InitWithMaximumPoint(limit, width);
        }

        private CBlade InitWithMaximumPoint(int limit , int width)
        {
            m_PointLimit = limit;
            m_Width = width;

            m_PosTexVerticeBuffer = new Vertex2DBuffer(2 * limit + 5);
            m_PosTexVerticeBuffer.SetVertexTexCoord(0, new Vector2(0, 0.5f));

            m_bDecreaseState = false;
            m_bEndState = false;
            m_Path = new List<Vector2>();

            return this;
        }

        public void Release()
        {
            m_Texture = null;

            m_PosTexVerticeBuffer.Release();

            m_Path.Clear();
            m_Path = null;
        }
              

        public void Push(Vector2 v)
        {
            if (m_bDecreaseState) return;

            if (m_Path.Count == 0)
            {
                m_Path.Insert(0, v);
                return;
            }

            Vector2 first = m_Path[0];

            if (Vector2.Distance(v, first) < DISTANCE_TO_INTERPOLATE)
            {
                m_Path.Insert(0, v);

                if (m_Path.Count > m_PointLimit)
                {
                    m_Path.RemoveAt(m_Path.Count - 1);
                }
            }

            else
            {
                int num = (int)(Vector2.Distance(v, first) / DISTANCE_TO_INTERPOLATE);
                Vector2 iv = Vector2.Multiply(Vector2.Subtract(v, first), (float)1.0 / (num + 1));
                for (int i = 1; i <= num + 1; i++)
                {
                    m_Path.Insert(0, Vector2.Add(first, Vector2.Multiply(iv, i)));
                }

                while (m_Path.Count > m_PointLimit)
                {
                    m_Path.RemoveAt(m_Path.Count - 1);
                }
            }

            PopulateVertices();
        }


        public bool GetEndState()
        {
            return m_bEndState;
        }

        private void SetEndState()
        {
            m_Path.Clear();
            m_bDecreaseState = false;
            m_bEndState = true;
        }

        
        private void PopulateVertices()
        {
            m_PosTexVerticeBuffer.SetVertexPos2D(0, m_Path[0]);
            Vector2 pre = m_PosTexVerticeBuffer.GetVertexPos2D(0);

            int i = 0;
            Vector2 it = m_Path[1];

            float dd = m_Width / m_Path.Count;

            while (i < m_Path.Count - 2)
            {
                Vertex2DUtil.f1(pre, it, m_Width - i * dd, m_PosTexVerticeBuffer, 2 * i + 1, 2 * i + 2);

                m_PosTexVerticeBuffer.SetVertexTexCoord(2 * i + 1, new Vector2(0.5f, 1.0f));
                m_PosTexVerticeBuffer.SetVertexTexCoord(2 * i + 2, new Vector2(0.5f, 0.0f));
                
                i++;
                pre = it;

                it = m_Path[i + 1];
            }

            m_PosTexVerticeBuffer.SetVertexTexCoord(1, new Vector2(0.25f, 1.0f));
            m_PosTexVerticeBuffer.SetVertexTexCoord(2, new Vector2(0.25f, 0.0f));

            m_PosTexVerticeBuffer.SetVertexPos2D(2 * m_Path.Count - 3, it);
            m_PosTexVerticeBuffer.SetVertexTexCoord(2 * m_Path.Count - 3, new Vector2(0.75f, 0.5f));
        }
       

        public void Update()
        {
            if (m_bDecreaseState && m_Path.Count > 0)
            {
                Pop(3);//꼬리 속도조절가능.
                if (m_Path.Count < 3)
                {
                    SetEndState();
                }
            }
        }
        private void Pop(int n)
        {
            while (m_Path.Count > 0 && n > 0)
            {
                m_Path.RemoveAt(m_Path.Count - 1);
                n--;
            }

            if (m_Path.Count > 2)
            {
                PopulateVertices();
            }
        }

        public void Draw()
        {
            if (m_Path.Count < 3)
                return;

            m_PosTexVerticeBuffer.Draw(m_Texture , m_PosTexVerticeBuffer.GetVertexArray(), 0, 2 * m_Path.Count - 4, nonCull);
        }

        public Vector2 GetTopPath()
        {
            return m_Path[0];
        }
    }
}
